package io.kiki.stack.http.feign;

/**
 * {@code ResponseInterceptor}s may be configured for purposes such as verifying or modifying
 * headers of response, verifying the business status of decoded object, or processing responses to
 * unsuccessful requests. Once the interceptors are applied, {@link
 * ResponseInterceptor#intercept(InvocationContext, ResponseInterceptorChain)} is called, then the response is decoded.
 */
public interface ResponseInterceptor {

    /**
     * Called by {@link ResponseHandler} after refreshing the response and wrapped around the whole
     * decode process, must either manually invoke {@link ResponseInterceptorChain#next(InvocationContext)} or manually
     * create a new response object
     *
     * @param invocationContext information surrounding the response being decoded
     * @return decoded response
     */
    Object intercept(InvocationContext invocationContext, ResponseInterceptorChain responseInterceptorChain) throws Exception;

    /**
     * Return a new {@link ResponseInterceptor} that invokes the current interceptor first and then
     * the one that is passed in.
     *
     * @param nextInterceptor the interceptor to delegate to after the current
     * @return a new interceptor that chains the two
     */
    default ResponseInterceptor andThen(ResponseInterceptor nextInterceptor) {
        return (invocationContext, responseInterceptorChain) -> intercept(invocationContext, nextContext -> nextInterceptor.intercept(nextContext, responseInterceptorChain));
    }

    /**
     * Apply this interceptor to the given {@code Chain} resulting in an intercepted chain.
     *
     * @param responseInterceptorChain the chain to add interception around
     * @return a new chain instance
     */
    default ResponseInterceptorChain apply(ResponseInterceptorChain responseInterceptorChain) {
        return invocationContext -> intercept(invocationContext, responseInterceptorChain);
    }

}
